package cn.webestar.scms.scheduling;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@Configuration
@EnableScheduling
@ConditionalOnClass({RedisOperations.class, RedisTemplate.class})
@EnableConfigurationProperties({SchedulingProperties.class})
public class SchedulingAutoConfig implements SchedulingConfigurer {

    @Autowired
    private SchedulingProperties properties;

    @Autowired(required = false)
    private SchedulingService scheduledService;

    @Autowired(required = false)
    private RedisTemplate<String, String> redisTemplate;

    private ExecutorService executorService = Executors.newCachedThreadPool();

    private String ipAddress;

    public SchedulingAutoConfig() {
        try {
            ipAddress = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        if (scheduledService == null) {
            log.warn("定时任务需要添加SchedulingService的实现类！");
            return;
        }
        if (redisTemplate == null) {
            log.warn("定时任务依赖RedisTemplate，需要提前实例化！");
            return;
        }
        List<SchedulingTask> tasks = scheduledService.getTask();
        if (tasks == null || tasks.isEmpty()) {
            log.warn("未添加任何定时任务！");
            return;
        }
        for (SchedulingTask task : tasks) {
            if (task.getLockTimeout() <= 0 || task.getLockTimeout() > 3600) {
                log.error("定时任务：{}，锁超时时间为：{}，不合理值，未加入到执行队列！(允许值为 0 < lockTimeout <= 3600)", task.getName(), task.getLockTimeout());
                continue;
            }
            CronTrigger trigger = new CronTrigger(task.getCron());
            taskRegistrar.addTriggerTask(() -> executeTask(task), trigger);
        }
    }

    private void executeTask(SchedulingTask task) {
        String lockKey = "lock:" + task.getName();
        Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked:" + ipAddress, Duration.ofSeconds(task.getLockTimeout()));
        if (Boolean.TRUE.equals(result)) {
            executorService.execute(() -> {
                log.debug("执行定时任务，时间:{}，corn:{}，名称:{}", LocalDateTime.now(), task.getCron(), task.getName());
                try {
                    scheduledService.executeTask(task);
                } finally {
                    redisTemplate.delete(lockKey);
                }
            });
        }
    }

}
